{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2019.04.12 Hasing\n",
    "\n",
    "Let's see how dataclasses implementing hashing.\n",
    "\n",
    "Then we can see if we can change it to use the `id` of objects if they are not hashable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import dataclasses"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@dataclasses.dataclass(frozen=True)\n",
    "class Something:\n",
    "    a: object\n",
    "    b: object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[0;31mSignature:\u001b[0m \u001b[0mSomething\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__hash__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
       "\u001b[0;31mDocstring:\u001b[0m <no docstring>\n",
       "\u001b[0;31mFile:\u001b[0m      Dynamically generated function. No source code available.\n",
       "\u001b[0;31mType:\u001b[0m      function\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "Something.__hash__??"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: DataclassInspector in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (1.0.1)\n",
      "Collecting black==18.9b0\n",
      "  Using cached https://files.pythonhosted.org/packages/2a/34/9938749f260a861cdd8427d63899e08f9a2a041159a26c2615b02828c973/black-18.9b0-py36-none-any.whl\n",
      "Requirement already satisfied: uncompyle6 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from DataclassInspector) (3.2.6)\n",
      "Requirement already satisfied: attrs>=17.4.0 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from black==18.9b0) (19.1.0)\n",
      "Requirement already satisfied: click>=6.5 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from black==18.9b0) (7.0)\n",
      "Requirement already satisfied: toml>=0.9.4 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from black==18.9b0) (0.10.0)\n",
      "Requirement already satisfied: appdirs in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from black==18.9b0) (1.4.3)\n",
      "Requirement already satisfied: xdis<3.10.0,>=3.9.0 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from uncompyle6->DataclassInspector) (3.9.1)\n",
      "Requirement already satisfied: spark-parser<1.9.0,>=1.8.7 in /usr/local/miniconda3/envs/metadsl/lib/python3.7/site-packages (from uncompyle6->DataclassInspector) (1.8.7)\n",
      "Installing collected packages: black\n",
      "  Found existing installation: black 19.3b0\n",
      "    Uninstalling black-19.3b0:\n",
      "      Successfully uninstalled black-19.3b0\n",
      "Successfully installed black-18.9b0\n"
     ]
    }
   ],
   "source": [
    "!pip install DataclassInspector \"black==18.9b0\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from DataclassInspector.inspector import Inspector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "from dataclasses import Field, _MISSING_TYPE, _DataclassParams\n",
      "\n",
      "\n",
      "class Something:\n",
      "    __dataclass_fields__ = {\n",
      "        \"a\": \"Field(name='a', type=object, default=_MISSING_TYPE, default_factory=_MISSING_TYPE, init=True, repr=True, hash=None, compare=True, metadata={}, _field_type=_FIELD)\",\n",
      "        \"b\": \"Field(name='b', type=object, default=_MISSING_TYPE, default_factory=_MISSING_TYPE, init=True, repr=True, hash=None, compare=True, metadata={}, _field_type=_FIELD)\",\n",
      "    }\n",
      "    __dataclass_params__ = _DataclassParams(\n",
      "        init=True,\n",
      "        repr=True,\n",
      "        eq=True,\n",
      "        order=False,\n",
      "        unsafe_hash=False,\n",
      "        frozen=True,\n",
      "    )\n",
      "\n",
      "    def __delattr__(self, name):\n",
      "        if type(self) is cls or name in (\"a\", \"b\"):\n",
      "            raise FrozenInstanceError(f\"\"\"cannot delete field {name!r}\"\"\")\n",
      "        super(cls, self).__delattr__(name)\n",
      "\n",
      "    a: object\n",
      "    b: object\n",
      "\n",
      "    def __eq__(self, other):\n",
      "        if other.__class__ is self.__class__:\n",
      "            return (self.a, self.b) == (other.a, other.b)\n",
      "        else:\n",
      "            return NotImplemented\n",
      "\n",
      "    def __hash__(self):\n",
      "        return hash((self.a, self.b))\n",
      "\n",
      "    def __init__(self, a: object, b: object) -> None:\n",
      "        __builtins__.object.__setattr__(self, \"a\", a)\n",
      "        __builtins__.object.__setattr__(self, \"b\", b)\n",
      "\n",
      "    def __repr__(self):\n",
      "        key = (id(self), _thread.get_ident())\n",
      "        if key in repr_running:\n",
      "            return \"...\"\n",
      "        else:\n",
      "            repr_running.add(key)\n",
      "            try:\n",
      "                result = user_function(self)\n",
      "            finally:\n",
      "                repr_running.discard(key)\n",
      "\n",
      "            return result\n",
      "\n",
      "    def __setattr__(self, name, value):\n",
      "        if type(self) is cls or name in (\"a\", \"b\"):\n",
      "            raise FrozenInstanceError(f\"\"\"cannot assign to field {name!r}\"\"\")\n",
      "        super(cls, self).__setattr__(name, value)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(Inspector(Something).code)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
